package com.swim.pay.web;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.jeesite.common.lang.StringUtils;
import com.swim.common.utils.ConstantUtil;
import com.swim.common.utils.MD5Utils;
import com.swim.common.utils.SmsUtil;
import com.swim.common.utils.WXPayUtil;
import com.swim.common.utils.XMLUtils;
import com.swim.pay.bean.AliPayBean;
import com.swim.pay.service.PayService;
import com.swim.shop.entity.Product;
import com.swim.shop.entity.ProductOrder;
import com.swim.shop.service.ProductOrderService;
import com.swim.shop.service.ProductService;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * @Author ljw
 * @Description 支付控制器类（平台产品）
 * @Date 23-5-28 下午8:35
 */
@Slf4j
@RestController
@RequestMapping(value = "${adminPath}/product/pay")
public class ProductPayController {

    private Logger logger = LoggerFactory.getLogger(ProductPayController.class);


    @Autowired
    private PayService payService;

	@Autowired
	private ProductOrderService productOrderService;
	
	@Autowired
	private ProductService productService;
	
    //#####################################################################
    //############################# 微信PC支付 #############################
    //#####################################################################

    /**
     * 微信支付url（PC端）
     * @param totalFee 金额
     * @param outTradeNo 订单号
     * @return
     * @throws Exception
     */
    @GetMapping("/get/vx/pay/url")
    @ResponseBody
    public Object weixinPcPayByQRCode(@RequestParam String totalFee, @RequestParam String outTradeNo) throws Exception {
    	ProductOrder where = new ProductOrder();
        where.setOrderNum(outTradeNo);
        List<ProductOrder> productOrderList = productOrderService.findList(where);
        HashMap<String, String> stringStringHashMap = new HashMap<>();
        if (productOrderList.size() > 0) {
            //应付金额
            Double shouldPay = productOrderList.get(0).getShouldPay();
            //判断金额是否和消费记录中一致
            if (StringUtils.isBlank(totalFee) || Double.parseDouble(totalFee) != shouldPay) {
                stringStringHashMap.put("status", "error");
                stringStringHashMap.put("message", "付款金额和订单订单金额不一致！");
                return stringStringHashMap;
            }
            Map<String, String> resultMap = payService.getWeixinPayCodeUrl(outTradeNo, totalFee, "NATIVE");
            return resultMap;
        }
    	stringStringHashMap.put("status", "error");
    	return stringStringHashMap;
    }
    
    /**
     * 查询微信支付状态
     * @param outTradeNo 订单号
     * @return
     * @throws Exception
     */
    @RequestMapping("/query/vx/pay/status")
    @ResponseBody
    public Object queryWeixinPayStatus(@RequestParam String outTradeNo) throws Exception {
        Map<String, String> resultMap = new HashMap<String, String>();
        while (true) {
            Map<String, String> map = payService.queryWeixinPayStatus(outTradeNo);
            if (map == null) {
                resultMap.put("status", "error");
                break;
            }
            if ("SUCCESS".equals(map.get("trade_state"))) {
                resultMap.put("status", "success");
            	ProductOrder where = new ProductOrder();
                where.setOrderNum(outTradeNo);
                List<ProductOrder> productOrderList = productOrderService.findList(where);
                orderPaySuccess(productOrderList.get(0));
                break;
            }
            Thread.sleep(3000);
        }
//        natatoriumOrderService.updateOrderStatus(outTradeNo, 2L);

        return resultMap;
    }

    /**
     * 更新订单支付状态(订单支付成功)
     * @param productOrder
     */
    public void orderPaySuccess(ProductOrder productOrder) {
    	//根据产品id查询产品
    	Product product = productService.get(productOrder.getProductId());
    	//用户在商城下单后通知李教练
		try {
			SmsUtil.mallOrderNotification(product.getProductTitle(), "13912785198");
		} catch (Exception e) {
			e.printStackTrace();
		}
    	//修改订单状态
    	productOrder.setOrderStatus(2L);// 订单状态 1表示未付款 2表示已付款 3表示已关闭
        productOrderService.update(productOrder);
        
        //更新商品库存
//        NatatoriumGoods natatoriumGoods = natatoriumGoodsService.get(natatoriumOrder.getNatatoriumGoodId());
//        natatoriumGoods.setNumber(natatoriumGoods.getNumber() - 1);
//        natatoriumGoodsService.update(natatoriumGoods);
    }

    //#####################################################################
    //############################# 微信H5支付 #############################
    //#####################################################################
    
    @ResponseBody
	@RequestMapping(value = "/get/vx/h5/pay/url" ,produces = { "application/json;charset=UTF-8" })
	public String weixinPayWap(HttpServletRequest request, HttpServletResponse response) throws Exception {
    	String subject = request.getParameter("subject");//前端上送的支付主题
    	String total_amount = request.getParameter("totalAmount");//前端上送的支付金额
    	String out_trade_no = request.getParameter("outTradeNo");//前端上送的订单号
    	
    	//判断支付金额是否和消费记录中一致
    	JSONObject result = new JSONObject();
    	ProductOrder where = new ProductOrder();
        where.setOrderNum(out_trade_no);
        List<ProductOrder> productOrderList = productOrderService.findList(where);
        if (productOrderList.size() > 0) {
            //应付金额
            Double shouldPay = productOrderList.get(0).getShouldPay();
            if (StringUtils.isBlank(total_amount) || Double.parseDouble(total_amount) != shouldPay) {
            	result.put("status", "error");
            	result.put("message", "付款金额和订单订单金额不一致！");
                return result.toString();
            }
        }
    	
//		String APPID = "wx23d5211634ee5234";//公众号的appid
//        String MERID = ConstantUtil.PARTNER_ID;//商户号
//        String SIGNKEY = ConstantUtil.PARTNER_KEY;//商户密钥
        
		String APPID = "wx23d5211634ee5234";//公众号的appid
        String MERID = "1454780102";//商户号
        String SIGNKEY = "YBy4MItTte3APraHjMgG5DO8eqEd5nDX";//商户密钥
		String spbill_create_ip = getIpAddr(request);//生产
		System.out.println("spbill_create_ip="+spbill_create_ip);
		//String spbill_create_ip = "";//测试地址，也就是本地真实ip，用于本地测试用
		String scene_info = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"www.szyypx.com\",\"wap_name\": \"信息认证\"}}";//我这里是网页入口，app入口参考文档的安卓和ios写法
		String tradeType = "MWEB";//H5支付标记
		//金额转化为分为单位 微信支付以分为单位
	    String finalmoney = com.swim.common.utils.StringUtils.getMoney(total_amount);
	    //随机数 
	    String nonce_str= MD5Utils.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());
//	    //签名数据
//	    StringBuilder sb = new StringBuilder();
//	    sb.append("appid="+APPID);
//	    sb.append("&body="+subject);
//	    sb.append("&mch_id="+MERID);
//	    sb.append("&nonce_str="+nonce_str);
//	    sb.append("&notify_url="+"http://www.szyypx.com/mobile/index.html#/pages/flyshark/my");//这里写回调地址
//	    sb.append("&out_trade_no="+out_trade_no);
//	    sb.append("&scene_info="+scene_info);
//	    sb.append("&sign_type="+"MD5");
//	    sb.append("&spbill_create_ip="+spbill_create_ip);
//	    sb.append("&total_fee="+finalmoney);
//	    sb.append("&trade_type="+tradeType);
//	    sb.append("&key="+SIGNKEY);
//	    System.out.println("sb="+sb);

	    //签名数据
	    StringBuilder sb = new StringBuilder();
	    sb.append("appid="+APPID);
	    sb.append("&body="+subject);
	    sb.append("&mch_id="+MERID);
	    sb.append("&nonce_str="+nonce_str);
	    sb.append("&notify_url="+"http://www.szyypx.com/swim/api/product/pay/notify");
	    sb.append("&out_trade_no="+out_trade_no);
	    sb.append("&scene_info="+scene_info);
	    sb.append("&sign_type="+"MD5");
	    sb.append("&spbill_create_ip="+spbill_create_ip);
	    sb.append("&total_fee="+finalmoney);
	    sb.append("&trade_type="+tradeType);
	    sb.append("&key="+SIGNKEY);
	    
	    //签名MD5加密  把sb.toString()做MD5操作并且toUpperCase()一下,至于怎么MD5,百度一下或者看官方文档";
	    String sign = WXPayUtil.MD5(sb.toString()).toUpperCase();
	    System.out.println("sign="+sign);
	    System.out.println("签名数据:"+sign);
	    //封装xml报文
	    String xml="<xml>"+//
	            "<appid>"+ APPID+"</appid>"+//
	            "<mch_id>"+ MERID+"</mch_id>"+//
	            "<nonce_str>"+nonce_str+"</nonce_str>"+//
	            "<sign>"+sign+"</sign>"+//
	            "<body>"+subject+"</body>"+//
	            "<out_trade_no>"+out_trade_no+"</out_trade_no>"+//
	            "<total_fee>"+finalmoney+"</total_fee>"+//
	            "<trade_type>"+tradeType+"</trade_type>"+//
//	            "<notify_url>"+"http://www.szyypx.com/swim/api/pay/notify"+"</notify_url>"+//这里写回调地址(通知地址)
//	            "<notify_url>"+ URLEncoder.encode("http://www.szyypx.com", "utf-8") +"</notify_url>"+//这里写回调地址(通知地址)
	            "<notify_url>"+"http://www.szyypx.com/swim/api/pay/notify"+"</notify_url>"+
	            "<sign_type>MD5</sign_type>"+//
	            "<scene_info>"+scene_info+"</scene_info>"+//
	            "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+//
	            "</xml>";
	    
	    System.out.println("########################");
	    System.out.println(xml);
	    System.out.println("########################");
	    
	    String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信统一下单接口
	    String mweb_url = "";
	    Map map = new HashMap();
	    try {
	    	//预下单 获取接口地址
	    	map = getMwebUrl(createOrderURL, xml);
    		String return_code  = (String) map.get("return_code");
	        String return_msg = (String) map.get("return_msg");
	        if("SUCCESS".equals(return_code) && "OK".equals(return_msg)){
	        	 mweb_url = (String) map.get("mweb_url");//调微信支付接口地址
	        	 System.out.println("mweb_url="+mweb_url);
	        }else{
	        	System.out.println("统一支付接口获取预支付订单出错");
	        	result.put("msg", "支付错误");
	        	return result.toString();
	        }
	    } catch (Exception e) {
	    	System.out.println("统一支付接口获取预支付订单出错");
	    	e.printStackTrace();
	        result.put("msg", "支付错误");
	        return result.toString();
	    }
	    //正常流程用户支付完成后会返回至发起支付的页面，如需返回至指定页面，则可以在MWEB_URL后拼接上redirect_url参数
	    result.put("mwebUrl",mweb_url + "&redirect_url="+ URLEncoder.encode("https://www.szyypx.com/mobile/#/pages/order/index?id=" + out_trade_no, "utf-8"));
		//添加微信支付记录日志等操作
		result.put("msg", "success");
		return result.toString();
	}

	 /**
	 * 获取用户实际ip
	 * @param request
	 * @return
	 */
	 public String getIpAddr(HttpServletRequest request){  
	    String ipAddress = request.getHeader("x-forwarded-for");  
	        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
	            ipAddress = request.getHeader("Proxy-Client-IP");  
	        }  
	        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
	            ipAddress = request.getHeader("WL-Proxy-Client-IP");  
	        }  
	        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
	            ipAddress = request.getRemoteAddr();  
	            if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){  
	                //根据网卡取本机配置的IP  
	                InetAddress inet=null;  
	                try {  
	                    inet = InetAddress.getLocalHost();  
	                } catch (UnknownHostException e) {  
	                    e.printStackTrace();  
	                }  
	                ipAddress= inet.getHostAddress();  
	            }  
	        }  
	        //对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割  
	        if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15  
	            if(ipAddress.indexOf(",")>0){  
	                ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));  
	            }  
	        }  
	        return ipAddress;   
	  }
	 
	 /**
	 * 回调接口 （接收通知）
	 * @param request
	 * @return
	 */
 	@RequestMapping(value = "/notify")
	public void weixinPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
		BufferedReader reader = request.getReader();
        String line = "";
        Map map = new HashMap();
        String xml = "<xml><return_code><![CDATA[FAIL]]></xml>";;
        JSONObject dataInfo = new JSONObject();
        StringBuffer inputString = new StringBuffer();
        while ((line = reader.readLine()) != null) {
            inputString.append(line);
        }
        request.getReader().close();
        System.out.println("----接收到的报文---"+inputString.toString());
        if(inputString.toString().length()>0){
        	 map = XMLUtils.parseXmlToList(inputString.toString());
        }else{
        	System.out.println("接受微信报文为空");
        }
        System.out.println("map="+map);
        if(map!=null && "SUCCESS".equals(map.get("result_code"))){
            //成功的业务。。。
        	String outTradeNo = (String) map.get("out_trade_no");//商户订单号,64个字符以内、可包含字母、数字、下划线；需保证在商户端不重复
        	System.out.println("----微信支付成功通知---outTradeNo =" + outTradeNo);
        	
            ProductOrder where = new ProductOrder();
            where.setOrderNum(outTradeNo);
            List<ProductOrder> productOrderList = productOrderService.findList(where);
            orderPaySuccess(productOrderList.get(0));
        	xml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        }else{
        	//失败的业务。。。
        	System.out.println("----微信支付失败通知---");
        }
        //告诉微信端已经确认支付成功
        response.getWriter().write(xml);
	}
 	
	/**
	 * 查询订单支付状态
	 * @param outTradeNo
	 * @return
	 */
	@GetMapping("/query/vx/h5/pay/status")
	public String orderStatusQuery(@RequestParam String outTradeNo) {
        ProductOrder where = new ProductOrder();
        where.setOrderNum(outTradeNo);
        List<ProductOrder> productOrderList = productOrderService.findList(where);
        
        if (CollectionUtils.isNotEmpty(productOrderList) && productOrderList.get(0).getOrderStatus() == 2L) {// 订单状态 2表示已付款
        	return "SUCCESS";
		}
        return "TRADE_NOT_EXIST";
	}

	public static Map getMwebUrl(String url,String xmlParam){
	  String jsonStr = null;
      HttpClient httpClient = new HttpClient();
      Map map = new HashMap();
      try {
    	 	PostMethod method = null;
			StringRequestEntity reqEntity = new StringRequestEntity(xmlParam,"text/json","UTF-8");
			method = new PostMethod(url);
			method.setRequestEntity(reqEntity);
			method.addRequestHeader("Content-Type","application/json;charset=utf-8");
			httpClient.executeMethod(method);
			StringBuffer resBodyBuf = new StringBuffer();
			byte[] responseBody = new byte[1024];
			int readCount = 0;
			BufferedInputStream is = new BufferedInputStream(method.getResponseBodyAsStream());
			while((readCount = is.read(responseBody,0,responseBody.length))!=-1){
				resBodyBuf.append(new String(responseBody,0,readCount,"utf-8"));
			}
			jsonStr = resBodyBuf.toString();
	        System.out.println(jsonStr);
	        map = XMLUtils.parseXmlToList(jsonStr);
	    } catch (Exception e) {
	        e.printStackTrace();
	    }
	    return map;
  }
	
    //#####################################################################
    //############################# 支付宝PC支付  ###########################
    //#####################################################################
    
    /**
     * 支付宝网页支付
     *
     * @param aliPayBean
     * @param response
     */
    @PostMapping("/alipay/webpage")
    public String rechargeAlipayWebPage(@RequestBody AliPayBean aliPayBean, HttpServletResponse response) {
        String paymentRequest = null;
        try {
            response.setContentType("text/html;charset=utf-8");
            paymentRequest = payService.mreadPaymentRequest(aliPayBean);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return paymentRequest;
    }

    /**
     * 支付宝接口回调
     *
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @PostMapping("/aliPay/callback")
    public String notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 返回数据
        /*
        gmt_create = 2021-01-30 19:46:39
        charset = UTF-8
        gmt_payment = 2021-01-30 19:46:50
        notify_time = 2021-01-30 19:46:51
        subject = 支付价格
        sign = aAfDqNi6U+UO32dV1g2aso
                buyer_id = 2088422
        body = 一笔订单
        invoice_amount = 0.01
        version = 1.0
        notify_id = 2021013000222194650069481
        fund_bill_list = [{"amount":"0.01","fundChannel":"ALIPAYACCOUNT"}]
        notify_type = trade_status_sync
        out_trade_no = 20210130074621-417586
        total_amount = 0.01
        trade_status = TRADE_SUCCESS
        trade_no = 2021013022001469481423016991
        auth_app_id = 20210011
        receipt_amount = 0.01
        point_amount = 0.00
        buyer_pay_amount = 0.01
        app_id = 20210011
        sign_type = RSA2
        seller_id = 208893165
        */

        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用
            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        String paramsJson = JSON.toJSONString(params);
        logger.error("支付宝回调，{}", paramsJson);
        try {
            // 调用SDK验证签名
            boolean signVerified = AlipaySignature.rsaCheckV1(params, ConstantUtil.alipay_public_key, ConstantUtil.charset, ConstantUtil.sign_type);
//            if (signVerified) {
                logger.error("支付宝回调签名认证成功=======================");
                // 按照支付结果异步通知中的描述，对支付结果中的业务内容进行1\2\3\4二次校验，校验成功后在response中返回success，校验失败返回failure

                // String passbackParams = params.get("passback_params");//商户传入业务信息，具体值要和支付宝约定，应用于安全，营销等参数直传场景，格式为json格式
                String outTradeNo = params.get("out_trade_no");//商户订单号,64个字符以内、可包含字母、数字、下划线；需保证在商户端不重复
                logger.error("======支付订单号========" + outTradeNo);
                String totalAmount = params.get("buyer_pay_amount");//订单总金额，单位为元，精确到小数点后两位，取值范围[0.01,100000000]。
                logger.error("======订单总金额========" + totalAmount);

                if ("TRADE_SUCCESS".equals(params.get("trade_status"))) {
                    ProductOrder where = new ProductOrder();
                    where.setOrderNum(outTradeNo);
                    List<ProductOrder> productOrderList = productOrderService.findList(where);
                    orderPaySuccess(productOrderList.get(0));
                }
                return "success";
//            } else {
//                logger.error("支付宝回调签名认证失败，signVerified=false, paramsJson:{}", paramsJson);
//                return "failure";
//            }
        } catch (AlipayApiException e) {
            logger.error("支付宝回调签名认证失败,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage());
            return "failure";
        }
    }
}
